/*
    This file is part of Posixcpp library.

    Posixcpp library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Posixcpp library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU LesserGeneral Public
    License along with Posixcpp library. If not, see
    <http://www.gnu.org/licenses/>.
*/

#include "posix_io_tty.hpp"

#include <unistd.h>
#include <sys/ioctl.h>

using posix::io::TTY;

using namespace posix;
using namespace posix::io;

TTY::BaudRate_t TTY::baudRateFromString( const std::string& str ) {
    
	if (str == "150")
		return TTY::BaudRate_t::BR_150;
	else if (str == "300")
		return TTY::BaudRate_t::BR_300;
	else if (str == "600")
		return TTY::BaudRate_t::BR_600;
	else if (str == "1200")
		return TTY::BaudRate_t::BR_1200;
	else if (str == "4800")
		return TTY::BaudRate_t::BR_4800;
	else if (str == "9600")
		return TTY::BaudRate_t::BR_9600;
	else if (str == "19200")
		return TTY::BaudRate_t::BR_19200;
	else if (str == "38400")
		return TTY::BaudRate_t::BR_38400;
	else if (str == "57600")
		return TTY::BaudRate_t::BR_57600;
	else if (str == "115200")
		return TTY::BaudRate_t::BR_115200;
	else
		return TTY::BaudRate_t::BR_HANGUP;
}

TTY::TTY() :
  m_baudRate(BaudRate_t::BR_HANGUP) {
    
	this->setCustomFlags(O_NOCTTY);
}

TTY::TTY(const std::string & fName, posix::io::TTY::BaudRate_t bRate) :
File(fName),
m_baudRate(bRate) {
    
	this->setCustomFlags(O_NOCTTY);
}

TTY::~TTY() {

}

void TTY::open() {
    termios config;
    
	File::open();
	
	POSIX_CALL_ASSERT_X( ::isatty(m_descriptor) == 1, "File is not a tty");
	POSIX_CALL_ASSERT_X( ::tcgetattr(m_descriptor, &config) != -1,
					 "Unable to get termios attributes");
	
	config.c_cflag = CREAD | CLOCAL | CS8;
	
	config.c_iflag = ICRNL;
	config.c_oflag = 0;
	
	::cfsetspeed(&config, uint(m_baudRate));
	
	config.c_lflag = 0;
	cfmakeraw(&config);
	
	config.c_cc[VMIN] = 1;
	config.c_cc[VTIME] = 0;
	
	POSIX_CALL_ASSERT_X( ::tcsetattr(m_descriptor, TCSANOW, &config) != -1,
					 "Could not set termios attributes");
}

void TTY::flush(QueueSelector_t queues) {
	POSIX_CALL_ASSERT( ::tcflush(m_descriptor, int(queues)) == 0);
}


namespace posix {
namespace io {
std::ostream & operator << (std::ostream & stream, TTY::BaudRate_t value)
{
	switch( value )
	{
	case TTY::BaudRate_t::BR_150 :
		stream << "150"; break;
	case TTY::BaudRate_t::BR_300 :
		stream << "300"; break;
	case TTY::BaudRate_t::BR_600 :
		stream << "600"; break;
	case TTY::BaudRate_t::BR_1200 :
		stream << "1200"; break;
	case TTY::BaudRate_t::BR_4800 :
		stream << "4800"; break;
	case TTY::BaudRate_t::BR_9600 :
		stream << "9600"; break;
	case TTY::BaudRate_t::BR_19200 :
		stream << "19200"; break;
	case TTY::BaudRate_t::BR_38400 :
		stream << "38400"; break;
	case TTY::BaudRate_t::BR_57600 :
		stream << "57600"; break;
	case TTY::BaudRate_t::BR_115200 :
		stream << "115200"; break;
	case TTY::BaudRate_t::BR_HANGUP :
		stream << "Hangup"; break;
	default:
		stream << "Undefined";
	}
	return stream;
}
}
}